﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BhServer.AppUpdate
{
    /// <summary>
    /// Application Version
    /// </summary>
    public class AppVersion : IComparable, IComparable<AppVersion>, IEquatable<AppVersion>
    {
        #region Properties
        
        /// <summary>
        /// Gets or sets the major number.
        /// </summary>
        /// <value>
        /// The major.
        /// </value>
        public int Major { get;  set; }
        /// <summary>
        /// Gets or sets the minor number.
        /// </summary>
        /// <value>
        /// The minor.
        /// </value>
        public int Minor { get;  set; }
        /// <summary>
        /// Gets or sets the patch number.
        /// </summary>
        /// <value>
        /// The patch.
        /// </value>
        public int Patch { get;  set; }
        /// <summary>
        /// Gets or sets the hotfix number.
        /// </summary>
        /// <value>
        /// The hotfix.
        /// </value>
        public int Hotfix { get;  set; }
        #endregion

        /// <summary>
        /// Returns formated version.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            string s = Major+"."+Minor;
            if (Patch > 0 || Hotfix > 0)
            {
                s += "." + Patch;
                if (Hotfix > 0)
                    s += "." + Hotfix;
            }
            return s;
        }

        #region CTOR
        /// <summary>
        /// Initializes a new instance of the <see cref="AppVersion"/> class.
        /// </summary>
        /// <param name="major">The major number.</param>
        /// <param name="minor">The minor number.</param>
        /// <param name="patch">The patch number.</param>
        /// <param name="hotfix">The hotfix number.</param>
        public AppVersion(int major, int minor = 0, int patch = 0, int hotfix = 0)
        {
            this.Major = major;
            Minor = minor;
            Patch = patch;
            Hotfix = hotfix;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AppVersion"/> class.
        /// </summary>
        /// <param name="version">The version.</param>
        public AppVersion(string version)
        {
            string[] parts = version.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length > 0)
            {
                Major = parts[0].AsInt();
                if (parts.Length > 1)
                {
                    Minor = parts[1].AsInt();
                    if (parts.Length > 2)
                    {
                        Patch = parts[2].AsInt();
                        if (parts.Length > 3)
                            Hotfix = parts[3].AsInt();
                    }
                }
            }
        }

        public AppVersion()
        {
        }
        #endregion

        public static bool operator ==(AppVersion v1, AppVersion v2)
        {
            if (object.ReferenceEquals((object)v1, (object)null))
                return object.ReferenceEquals((object)v2, (object)null);
            else
                return v1.Equals(v2);
        }

        /// <summary>
        /// Determines whether two specified <see cref="T:System.Version"/> objects are not equal.
        /// </summary>
        /// 
        /// <returns>
        /// true if <paramref name="v1"/> does not equal <paramref name="v2"/>; otherwise, false.
        /// </returns>
        /// <param name="v1">The first <see cref="T:System.Version"/> object. </param><param name="v2">The second <see cref="T:System.Version"/> object. </param><filterpriority>3</filterpriority>
        public static bool operator !=(AppVersion v1, AppVersion v2)
        {
            return !(v1 == v2);
        }

        public static bool operator <(AppVersion v1, AppVersion v2)
        {
            if (v1 == null)
                throw new ArgumentNullException("v1");
            else
                return v1.CompareTo(v2) < 0;
        }
        public static bool operator <=(AppVersion v1, AppVersion v2)
        {
            if (v1 == null)
                throw new ArgumentNullException("v1");
            else
                return v1.CompareTo(v2) <= 0;
        }

        public static bool operator >(AppVersion v1, AppVersion v2)
        {
            return v2 < v1;
        }


        public static bool operator >=(AppVersion v1, AppVersion v2)
        {
            return v2 <= v1;
        }
        public int CompareTo(object version)
        {
            if (version == null)
                return 1;
            AppVersion version1 = version as AppVersion;
            if (version1 == (AppVersion)null)
                throw new ArgumentException("version is not AppVersion");
            if (this.Major != version1.Major)
                return this.Major > version1.Major ? 1 : -1;
            else if (this.Minor != version1.Minor)
                return this.Minor > version1.Minor ? 1 : -1;
            else if (this.Patch != version1.Patch)
            {
                return this.Patch > version1.Patch ? 1 : -1;
            }
            else
            {
                if (this.Hotfix == version1.Hotfix)
                    return 0;
                return this.Hotfix > version1.Hotfix ? 1 : -1;
            }
        }

        public int CompareTo(AppVersion value)
        {
            if (value == (AppVersion)null)
                return 1;
            if (this.Major != value.Major)
                return this.Major > value.Major ? 1 : -1;
            else if (this.Minor != value.Minor)
                return this.Minor > value.Minor ? 1 : -1;
            else if (this.Patch != value.Patch)
            {
                return this.Patch > value.Patch ? 1 : -1;
            }
            else
            {
                if (this.Hotfix == value.Hotfix)
                    return 0;
                return this.Hotfix > value.Hotfix ? 1 : -1;
            }
        }

        public override bool Equals(object obj)
        {
            AppVersion version = obj as AppVersion;
            return !(version == (AppVersion)null) && this.Major == version.Major && (this.Minor == version.Minor && this.Patch == version.Patch) && this.Hotfix == version.Hotfix;
        }

        public bool Equals(AppVersion obj)
        {
            if (obj == null)
                return false;
            return !(obj == (AppVersion)null) && this.Major == obj.Major && (this.Minor == obj.Minor && this.Patch == obj.Patch) && this.Hotfix == obj.Hotfix;
        }

        public override int GetHashCode()
        {
            return (this.Major & 15) << 28 | (this.Minor & (int)byte.MaxValue) << 20 | (this.Patch & (int)byte.MaxValue) << 12 | this.Hotfix & 4095;
        }
    }
}
